package com.ferry.transport.netty.provider;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.kqueue.KQueue;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.ThreadFactory;

/**
 * Created by daiyong
 */
public abstract class NettyTcpAcceptor extends NettyAcceptor {

	private static final Logger logger = LoggerFactory.getLogger(NettyTcpAcceptor.class);

	private final boolean isNative; // use native transport

	public NettyTcpAcceptor(int port, int nWorkers) {
		super(new InetSocketAddress(port), nWorkers);
		isNative = false;
		init();
	}

	public NettyTcpAcceptor(int port, int nBosses, int nWorkers) {
		super(new InetSocketAddress(port), nBosses, nWorkers);
		isNative = false;
		init();
	}

	public NettyTcpAcceptor(SocketAddress localAddress, int nWorkers) {
		super(localAddress, nWorkers);
		isNative = false;
		init();
	}

	public NettyTcpAcceptor(SocketAddress localAddress, int nBosses, int nWorkers) {
		super(localAddress, nBosses, nWorkers);
		isNative = false;
		init();
	}

	public NettyTcpAcceptor(int port, int nWorkers, boolean isNative) {
		super(new InetSocketAddress(port), nWorkers);
		this.isNative = isNative;
		init();
	}

	public NettyTcpAcceptor(int port, int nBosses, int nWorkers, boolean isNative) {
		super(new InetSocketAddress(port), nBosses, nWorkers);
		this.isNative = isNative;
		init();
	}

	public NettyTcpAcceptor(SocketAddress localAddress, int nWorkers, boolean isNative) {
		super(localAddress, nWorkers);
		this.isNative = isNative;
		init();
	}

	public NettyTcpAcceptor(SocketAddress localAddress, int nBosses, int nWorkers, boolean isNative) {
		super(localAddress, nBosses, nWorkers);
		this.isNative = isNative;
		init();
	}

	private void setTcpOptions() {
		ServerBootstrap boot = serverBootstrap();
		//boot 设置参数
	}

	@Override
	public void start() throws InterruptedException {
		start(true);
	}

	@Override
	public void start(boolean sync) throws InterruptedException {
		ChannelFuture future = bind(localAddress).sync();
		if (sync) {
			future.channel().closeFuture().sync();
		}
	}

	@Override
	protected EventLoopGroup initEventLoopGroup(int nThreads, ThreadFactory tFactory) {
		SocketChannelProvider.SocketType socketType = socketType();
		switch (socketType) {
			case NATIVE_EPOLL:
				return new EpollEventLoopGroup(nThreads, tFactory);
			case NATIVE_KQUEUE:
				return new KQueueEventLoopGroup(nThreads, tFactory);
			case JAVA_NIO:
				return new NioEventLoopGroup(nThreads, tFactory);
			default:
				throw new IllegalStateException("Invalid socket type: " + socketType);
		}
	}

	protected void initChannelFactory() {
		SocketChannelProvider.SocketType socketType = socketType();
		switch (socketType) {
			case NATIVE_EPOLL:
				serverBootstrap().channelFactory(SocketChannelProvider.NATIVE_EPOLL_ACCEPTOR);
				break;
			case NATIVE_KQUEUE:
				serverBootstrap().channelFactory(SocketChannelProvider.NATIVE_KQUEUE_ACCEPTOR);
				break;
			case JAVA_NIO:
				serverBootstrap().channelFactory(SocketChannelProvider.JAVA_NIO_ACCEPTOR);
				break;
			default:
				throw new IllegalStateException("Invalid socket type: " + socketType);
		}
	}

	protected SocketChannelProvider.SocketType socketType() {
		if (isNative && Epoll.isAvailable()) {
			return SocketChannelProvider.SocketType.NATIVE_EPOLL;
		}
		if (isNative && KQueue.isAvailable()) {
			return SocketChannelProvider.SocketType.NATIVE_KQUEUE;
		}
		return SocketChannelProvider.SocketType.JAVA_NIO;
	}


}
